This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

#import libraries
library(plyr)
library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.2.0     ✔ purrr   0.3.2
✔ tibble  2.1.1     ✔ dplyr   0.8.3
✔ tidyr   0.8.3     ✔ stringr 1.4.0
✔ readr   1.3.1     ✔ forcats 0.4.0
── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::arrange()   masks plyr::arrange()
✖ purrr::compact()   masks plyr::compact()
✖ dplyr::count()     masks plyr::count()
✖ dplyr::failwith()  masks plyr::failwith()
✖ dplyr::filter()    masks stats::filter()
✖ dplyr::id()        masks plyr::id()
✖ dplyr::lag()       masks stats::lag()
✖ dplyr::mutate()    masks plyr::mutate()
✖ dplyr::rename()    masks plyr::rename()
✖ dplyr::summarise() masks plyr::summarise()
✖ dplyr::summarize() masks plyr::summarize()
library(dplyr)
library(corrplot)
corrplot 0.84 loaded
library(ggplot2)
library(ggcorrplot)
library(data.table)
data.table 1.12.2 using 2 threads (see ?getDTthreads).  Latest news: r-datatable.com

Attaching package: ‘data.table’

The following objects are masked from ‘package:dplyr’:

    between, first, last

The following object is masked from ‘package:purrr’:

    transpose
#Import dataset diemthi2019.csv
diemthi2019 <- read.csv('~/Desktop/2019 vietnam national high school exam/diemthi2019.csv', row.names = NULL)
#Choose necessary columns and reorder them
head(diemthi2019)
str(diemthi2019)
'data.frame':   811851 obs. of  12 variables:
 $ X               : int  0 1 2 3 4 5 6 7 8 9 ...
 $ Dia             : num  7.75 NA 4.25 4.75 8.25 NA NA 6.25 NA 7.5 ...
 $ GDCD            : num  8.75 NA 5.75 5 7.5 NA NA 8.75 NA 8.5 ...
 $ Hoa             : num  NA 4.5 NA NA NA 5.75 NA NA 3.5 NA ...
 $ Li              : num  NA 8.25 NA NA NA 7.5 NA NA 5.5 NA ...
 $ Ma_mon_ngoai_ngu: Factor w/ 7 levels "","N1","N2","N3",..: 2 2 1 1 2 2 1 2 2 2 ...
 $ Ngoai_ngu       : num  7.6 8 NA NA 4.4 4.4 NA 8.8 2.2 5.2 ...
 $ Sinh            : num  NA 6 NA NA NA 3 NA NA 3.75 NA ...
 $ Su              : num  8.25 NA 4 2.25 7.75 NA 3.25 5.25 NA 3.25 ...
 $ Toan            : num  8.2 8.6 5.2 4.4 5.8 7.2 2.2 5 5.6 6.6 ...
 $ Van             : num  8 6.17 4.75 4.5 6 6.75 5.75 6.5 4.5 7 ...
 $ sbd             : int  24008611 51000032 51000005 51000021 51000013 51000003 51000001 51000011 51000007 51000010 ...
#Import and modify dataset province_code.csv
province_code <- read.csv('~/Desktop/2019 vietnam national high school exam/province_code.csv', sep = ";", row.names = NULL)
#Change column type of province_code.csv
province_code$Province_code <- as.numeric(province_code$Province_code)
province_code$Province_name <- as.factor(province_code$Province_name)
head(province_code)
str(province_code)
'data.frame':   64 obs. of  2 variables:
 $ Province_code: num  1 2 3 4 5 6 7 8 9 10 ...
 $ Province_name: Factor w/ 63 levels "","An Giang",..: 24 29 27 16 22 15 35 38 60 37 ...
#Change column name for diemthi2019.csv
diemthi2019 <- plyr::rename(diemthi2019, c(
    'sbd' = 'Student_index',
    'Toan'= 'Maths',
    'Van' = 'Literature',
    'Ngoai_ngu' = 'Foreign_language',
    'Ma_mon_ngoai_ngu' = 'Foreign_language_code',
    'Li' = 'Physics',
    'Hoa' = 'Chemistry',
    'Sinh' = 'Biology',
    'Su' = 'History',
    'Dia' = 'Geography',
    'GDCD' = 'Citizenship_education'
    )
  )
head(diemthi2019)
#Insert province_code for diemthi2019.csv
Province_code <- ifelse(diemthi2019$Student_index > 10000000,
            substr(as.character(diemthi2019$Student_index), start = 1, stop = 2),
            substr(as.character(diemthi2019$Student_index), start = 1, stop = 1)
)
diemthi2019$Province_code <- as.numeric(Province_code)
#insert foreign language names with respect to code
diemthi2019$Foreign_language_name <- diemthi2019$Foreign_language_code
diemthi2019$Foreign_language_name <- mapvalues(diemthi2019$Foreign_language_code, from=c("N1", "N2", "N3", "N4", "N5", "N6"), to=c("English", "Russian", "French", "Chinese", "German", "Japanese"))
head(diemthi2019)
#Merge diemthi2019.csv and province_code.csv
diemthi2019 <- join(diemthi2019, province_code, by = "Province_code")
head(diemthi2019)
#Calculate scores of combinations A00, A01, B00, C00, D00
diemthi2019$A00 <- diemthi2019$Maths + diemthi2019$Physics + diemthi2019$Chemistry
if(diemthi2019$Foreign_language_code == 'N1') {
  diemthi2019$A01 <- diemthi2019$Maths + diemthi2019$Physics + diemthi2019$Foreign_language
}
the condition has length > 1 and only the first element will be used
diemthi2019$B00 <- diemthi2019$Maths + diemthi2019$Chemistry + diemthi2019$Biology
diemthi2019$C00 <- diemthi2019$Literature + diemthi2019$History + diemthi2019$Geography
if(diemthi2019$Foreign_language_code == 'N1') {
  diemthi2019$D00 <- diemthi2019$Maths + diemthi2019$Literature + diemthi2019$Foreign_language
}
the condition has length > 1 and only the first element will be used
head(diemthi2019)
#Calculate average of natural science combination and social science combination
diemthi2019$Avg_natural_sciences <- (diemthi2019$Physics + diemthi2019$Chemistry + diemthi2019$Biology)/3
diemthi2019$Avg_social_sciences <- (diemthi2019$History + diemthi2019$Geography + diemthi2019$Citizenship_education)/3
#Reorder and choose necessary columns
diemthi2019 <- diemthi2019[c('Student_index', 'Province_code', 'Province_name', 'Maths', 'Literature', 'Foreign_language' ,'Foreign_language_code', 'Foreign_language_name', 'Physics', 'Chemistry', 'Biology', 'Avg_natural_sciences', 'History', 'Geography', 'Citizenship_education', 'Avg_social_sciences', 'A00', 'A01', 'B00', 'C00', 'D00')]
head(diemthi2019)
#numerical df for correlation matrix
diemthi2019_corr <- diemthi2019[c(4:6,9:21)]
#correlation matrix
diemthi2019_corr_matrix <- cor(diemthi2019_corr, use="pairwise.complete.obs")
View(diemthi2019_corr_matrix)
#correlation heatmap
ggcorrplot(diemthi2019_corr_matrix, hc.order = TRUE,
   lab = TRUE)

#Number of students who takes each foreign language test
table(diemthi2019$Foreign_language_name)

          English  Russian   French  Chinese   German Japanese 
   83338   726064      148      646      801       81      773 
#Number of students who took each subject
took_subject <- list()
for(i in c(4:6, 9:11, 13:15)) {
  print(paste('The number of students who took the subject', colnames(diemthi2019[i]), 'is', sum(!is.na(diemthi2019[,i]) == TRUE))) 
}
[1] "The number of students who took the subject Maths is 807762"
[1] "The number of students who took the subject Literature is 799208"
[1] "The number of students who took the subject Foreign_language is 728513"
[1] "The number of students who took the subject Physics is 292166"
[1] "The number of students who took the subject Chemistry is 295544"
[1] "The number of students who took the subject Biology is 291199"
[1] "The number of students who took the subject History is 542729"
[1] "The number of students who took the subject Geography is 535897"
[1] "The number of students who took the subject Citizenship_education is 470905"
#Number of students who are eligible to be considered for admission with each combination A00, A01, B00, C00, D00
combination_eligible <- list()
for(i in c(17:21)) {
  print(paste('The number of students who are eligible to be considered for combination', colnames(diemthi2019[i]), 'is', sum(!is.na(diemthi2019[,i]) == TRUE))) 
  combination_eligible[[i-16]] = table(!is.na(diemthi2019[,i]), dnn = paste(colnames(diemthi2019)[i]))
}
[1] "The number of students who are eligible to be considered for combination A00 is 290759"
[1] "The number of students who are eligible to be considered for combination A01 is 281100"
[1] "The number of students who are eligible to be considered for combination B00 is 291078"
[1] "The number of students who are eligible to be considered for combination C00 is 535427"
[1] "The number of students who are eligible to be considered for combination D00 is 725824"
combination_eligible
[[1]]
A00
 FALSE   TRUE 
521092 290759 

[[2]]
A01
 FALSE   TRUE 
530751 281100 

[[3]]
B00
 FALSE   TRUE 
520773 291078 

[[4]]
C00
 FALSE   TRUE 
276424 535427 

[[5]]
D00
 FALSE   TRUE 
 86027 725824 
#Number of students who took all natural science subjects, all social science subjects, or all of both
print(paste('The number of students who took all natural science subjects is', sum(!is.na(diemthi2019[,13]) == TRUE)))
[1] "The number of students who took all natural science subjects is 542729"
print(paste('The number of students who took all social science subjects is', sum(!is.na(diemthi2019[,17]) == TRUE)))
[1] "The number of students who took all social science subjects is 290759"
print(paste('The number of students who took all natural and social science subjects is', sum(!is.na(diemthi2019[,13]) == TRUE & !is.na(diemthi2019[,17]) == TRUE)))
[1] "The number of students who took all natural and social science subjects is 30746"
#Find the maximum score for each column
for(i in c(4:6,9:21)) {
  print(paste('The maximum score of',colnames(diemthi2019)[i],'is', max(diemthi2019[,i], na.rm = TRUE)))
}
[1] "The maximum score of Maths is 10"
[1] "The maximum score of Literature is 9.5"
[1] "The maximum score of Foreign_language is 10"
[1] "The maximum score of Physics is 10"
[1] "The maximum score of Chemistry is 10"
[1] "The maximum score of Biology is 10"
[1] "The maximum score of Avg_natural_sciences is 9.41666666666667"
[1] "The maximum score of History is 10"
[1] "The maximum score of Geography is 10"
[1] "The maximum score of Citizenship_education is 10"
[1] "The maximum score of Avg_social_sciences is 9.83333333333333"
[1] "The maximum score of A00 is 29.05"
[1] "The maximum score of A01 is 28.9"
[1] "The maximum score of B00 is 29.8"
[1] "The maximum score of C00 is 28.75"
[1] "The maximum score of D00 is 28.4"
histogram_out <- list()
for(i in c(4:6,9:21)) {
  x = diemthi2019[,i]
  histogram_out[[i]] <- ggplot(data.frame(x), aes(x)) + 
    geom_histogram(binwidth = 0.1, color="black", fill="blue") +
    labs(title=paste("Score histogram for",colnames(diemthi2019)[i]), x=colnames(diemthi2019)[i], y="Count") + 
    geom_vline(data = diemthi2019, xintercept = mean(diemthi2019[,i], na.rm = TRUE), color = "red", linetype = "dashed", size = 1)
}
histogram_out
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]

[[5]]

[[6]]

[[7]]
NULL

[[8]]
NULL

[[9]]

[[10]]

[[11]]

[[12]]

[[13]]

[[14]]

[[15]]

[[16]]

[[17]]

[[18]]

[[19]]

[[20]]

[[21]]

histogram_out <- list()
for(i in c(4:6,9:21)) {
  x = diemthi2019[,i]
  histogram_out[[i]] <- ggplot(data.frame(x), aes(x)) + 
    geom_histogram(binwidth = 0.1, color="black", fill="blue") +
    labs(title=paste("Score histogram for",colnames(diemthi2019)[i]), x=colnames(diemthi2019)[i], y="Count") + 
    geom_vline(data = diemthi2019, xintercept = mean(diemthi2019[,i], na.rm = TRUE), color = "red", linetype = "dashed", size = 1)
  print(histogram_out[[i]])
  print(paste('The mean score of', colnames(diemthi2019)[i], 'is', mean(diemthi2019[,i])))
}
[1] "The mean score of Maths is NA"
[1] "The mean score of Literature is NA"
[1] "The mean score of Foreign_language is NA"
[1] "The mean score of Physics is NA"
[1] "The mean score of Chemistry is NA"
[1] "The mean score of Biology is NA"
[1] "The mean score of Avg_natural_sciences is NA"
[1] "The mean score of History is NA"
[1] "The mean score of Geography is NA"
[1] "The mean score of Citizenship_education is NA"
[1] "The mean score of Avg_social_sciences is NA"
[1] "The mean score of A00 is NA"
[1] "The mean score of A01 is NA"
[1] "The mean score of B00 is NA"
[1] "The mean score of C00 is NA"
[1] "The mean score of D00 is NA"

NA
NA
summary(diemthi2019[,3])
                           An Giang Ba Ria - Vung Tau         Bac Giang           Bac Kan          Bac Lieu          Bac Ninh 
                0             15784             11221             19554              2849              5355             14276 
          Ben Tre        Binh Dinh         Binh Duong        Binh Phuoc        Binh Thuan            Ca Mau           Can Tho 
            11316             17773             10854              9705             10885              9292             10471 
         Cao Bang          Da Nang           Dak Lak           Dak Nong         Dien Bien         Dong Nai          Dong Thap 
             4741             23290             20471              6292              5287             27525             13098 
        Ha Giang             Ha Nam           Ha Noi           Ha Tinh          Hai Duong         Hai Phong         Hau Giang 
             5155              8583             74277             16821             19248             18484              5707 
     Ho Chi Minh          Hoa Binh          Hung Yen         Khanh Hoa         Kien Giang           Kon Tum          Lai Chau 
                0              8949             12356             12546             12468              4305              3231 
        Lam Dong           Lang Son           Lao Cao           Long An         Nam Dinh            Nghe An         Ninh Binh 
            13888              8830              6230             13350             18275             32242              8948 
       Ninh Thuan           Phu Tho           Phu Yen        Quang Binh         Quang Nam        Quang Ngai        Quang Ninh 
             5448             13635             10311             10385             16346             12690             14108 
        Quang Tri         Soc Trang            Son La          Tay Ninh        Thai Binh        Thai Nguyen        Thanh Hoa  
             7873              8759             10551              8722             18986             14348             34886 
   Thua Thien Hue        Tien Giang          Tra Vinh       Tuyen Quang        Vinh Long          Vinh Phuc           Yen Bai 
            11881             13744              7840              7867             10274             12241              7024 
province_frequency <- table(diemthi2019[,3])
 #sort(province_frequency, decreasing = FALSE) 
province_frequency <-count(diemthi2019, Province_name)
names(province_frequency) <- c('Province', 'Frequency')
province_frequency <- province_frequency[order(-province_frequency$Frequency),]
par(las=2)
View(province_frequency)
ggplot(data=province_frequency, aes(x=reorder(Province,Frequency),y=Frequency)) +
  geom_bar(position="dodge", stat="identity") + 
  coord_flip() +
  ggtitle(paste('Barplot of number of students by province')) +
  labs(x = "Province", y = "Number of students") +
  geom_text(
    aes(label = Frequency), colour = "red", 
    hjust = -0.5, size = 3,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  )

barplot_mean <- list()
for(i in c(4:6,9:21)) {
  x <- aggregate(diemthi2019[,i] ~ diemthi2019$Province_name, diemthi2019, mean)
  names(x) <- c('Province', 'Mean')
  x <- x[order(x$Mean),]
  
  barplot_mean[[i]] <- ggplot(data=x, aes(x=reorder(Province,Mean),y=Mean)) +
  geom_bar(position="dodge",stat="identity") + 
  coord_flip() +
  ggtitle(paste('Barplot for mean of', colnames(diemthi2019)[i], 'by province')) + 
  labs(x = "Province", y = "Mean score") +
  geom_text(
    aes(label = Mean), colour = "red",
    hjust = -0.5, size = 3,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  )
}
barplot_mean
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]

[[5]]

[[6]]

[[7]]
NULL

[[8]]
NULL

[[9]]

[[10]]

[[11]]

[[12]]

[[13]]

[[14]]

[[15]]

[[16]]

[[17]]

[[18]]

[[19]]

[[20]]

[[21]]

LS0tCnRpdGxlOiAiMjAxOSBWaWV0bmFtIEhpZ2ggU2Nob29sIE5hdGlvbmFsIEdyYWR1YXRpb24gRXhhbSBzY29yZSBhbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjoKICAtIG5hbWU6IEhvYW5nIEFuaCBOR08KICAtIGFmZmlsaWF0aW9uOiBFY29sZSBQb2x5dGVjaG5pcXVlLCBJUCBQYXJpcwotLS0KClRoaXMgaXMgYW4gW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIE5vdGVib29rLiBXaGVuIHlvdSBleGVjdXRlIGNvZGUgd2l0aGluIHRoZSBub3RlYm9vaywgdGhlIHJlc3VsdHMgYXBwZWFyIGJlbmVhdGggdGhlIGNvZGUuIAoKVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkNtZCtTaGlmdCtFbnRlciouIAoKCmBgYHtyfQojaW1wb3J0IGxpYnJhcmllcwpsaWJyYXJ5KHBseXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGNvcnJwbG90KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2djb3JycGxvdCkKbGlicmFyeShkYXRhLnRhYmxlKQpgYGAKCgpgYGB7cn0KI0ltcG9ydCBkYXRhc2V0IGRpZW10aGkyMDE5LmNzdgpkaWVtdGhpMjAxOSA8LSByZWFkLmNzdignfi9EZXNrdG9wLzIwMTkgdmlldG5hbSBuYXRpb25hbCBoaWdoIHNjaG9vbCBleGFtL2RpZW10aGkyMDE5LmNzdicsIHJvdy5uYW1lcyA9IE5VTEwpCgojQ2hvb3NlIG5lY2Vzc2FyeSBjb2x1bW5zIGFuZCByZW9yZGVyIHRoZW0KaGVhZChkaWVtdGhpMjAxOSkKc3RyKGRpZW10aGkyMDE5KQoKI0ltcG9ydCBhbmQgbW9kaWZ5IGRhdGFzZXQgcHJvdmluY2VfY29kZS5jc3YKcHJvdmluY2VfY29kZSA8LSByZWFkLmNzdignfi9EZXNrdG9wLzIwMTkgdmlldG5hbSBuYXRpb25hbCBoaWdoIHNjaG9vbCBleGFtL3Byb3ZpbmNlX2NvZGUuY3N2Jywgc2VwID0gIjsiLCByb3cubmFtZXMgPSBOVUxMKQoKI0NoYW5nZSBjb2x1bW4gdHlwZSBvZiBwcm92aW5jZV9jb2RlLmNzdgpwcm92aW5jZV9jb2RlJFByb3ZpbmNlX2NvZGUgPC0gYXMubnVtZXJpYyhwcm92aW5jZV9jb2RlJFByb3ZpbmNlX2NvZGUpCnByb3ZpbmNlX2NvZGUkUHJvdmluY2VfbmFtZSA8LSBhcy5mYWN0b3IocHJvdmluY2VfY29kZSRQcm92aW5jZV9uYW1lKQoKaGVhZChwcm92aW5jZV9jb2RlKQpzdHIocHJvdmluY2VfY29kZSkKYGBgCgoKYGBge3J9CiNDaGFuZ2UgY29sdW1uIG5hbWUgZm9yIGRpZW10aGkyMDE5LmNzdgpkaWVtdGhpMjAxOSA8LSBwbHlyOjpyZW5hbWUoZGllbXRoaTIwMTksIGMoCiAgICAnc2JkJyA9ICdTdHVkZW50X2luZGV4JywKICAgICdUb2FuJz0gJ01hdGhzJywKICAgICdWYW4nID0gJ0xpdGVyYXR1cmUnLAogICAgJ05nb2FpX25ndScgPSAnRm9yZWlnbl9sYW5ndWFnZScsCiAgICAnTWFfbW9uX25nb2FpX25ndScgPSAnRm9yZWlnbl9sYW5ndWFnZV9jb2RlJywKICAgICdMaScgPSAnUGh5c2ljcycsCiAgICAnSG9hJyA9ICdDaGVtaXN0cnknLAogICAgJ1NpbmgnID0gJ0Jpb2xvZ3knLAogICAgJ1N1JyA9ICdIaXN0b3J5JywKICAgICdEaWEnID0gJ0dlb2dyYXBoeScsCiAgICAnR0RDRCcgPSAnQ2l0aXplbnNoaXBfZWR1Y2F0aW9uJwogICAgKQogICkKaGVhZChkaWVtdGhpMjAxOSkKYGBgCgpgYGB7cn0KI0luc2VydCBwcm92aW5jZV9jb2RlIGZvciBkaWVtdGhpMjAxOS5jc3YKUHJvdmluY2VfY29kZSA8LSBpZmVsc2UoZGllbXRoaTIwMTkkU3R1ZGVudF9pbmRleCA+IDEwMDAwMDAwLAogICAgICAgICAgICBzdWJzdHIoYXMuY2hhcmFjdGVyKGRpZW10aGkyMDE5JFN0dWRlbnRfaW5kZXgpLCBzdGFydCA9IDEsIHN0b3AgPSAyKSwKICAgICAgICAgICAgc3Vic3RyKGFzLmNoYXJhY3RlcihkaWVtdGhpMjAxOSRTdHVkZW50X2luZGV4KSwgc3RhcnQgPSAxLCBzdG9wID0gMSkKKQpkaWVtdGhpMjAxOSRQcm92aW5jZV9jb2RlIDwtIGFzLm51bWVyaWMoUHJvdmluY2VfY29kZSkKCiNpbnNlcnQgZm9yZWlnbiBsYW5ndWFnZSBuYW1lcyB3aXRoIHJlc3BlY3QgdG8gY29kZQpkaWVtdGhpMjAxOSRGb3JlaWduX2xhbmd1YWdlX25hbWUgPC0gZGllbXRoaTIwMTkkRm9yZWlnbl9sYW5ndWFnZV9jb2RlCmRpZW10aGkyMDE5JEZvcmVpZ25fbGFuZ3VhZ2VfbmFtZSA8LSBtYXB2YWx1ZXMoZGllbXRoaTIwMTkkRm9yZWlnbl9sYW5ndWFnZV9jb2RlLCBmcm9tPWMoIk4xIiwgIk4yIiwgIk4zIiwgIk40IiwgIk41IiwgIk42IiksIHRvPWMoIkVuZ2xpc2giLCAiUnVzc2lhbiIsICJGcmVuY2giLCAiQ2hpbmVzZSIsICJHZXJtYW4iLCAiSmFwYW5lc2UiKSkKCmhlYWQoZGllbXRoaTIwMTkpCmBgYAoKYGBge3J9CiNNZXJnZSBkaWVtdGhpMjAxOS5jc3YgYW5kIHByb3ZpbmNlX2NvZGUuY3N2CmRpZW10aGkyMDE5IDwtIGpvaW4oZGllbXRoaTIwMTksIHByb3ZpbmNlX2NvZGUsIGJ5ID0gIlByb3ZpbmNlX2NvZGUiKQpoZWFkKGRpZW10aGkyMDE5KQpgYGAKCgpgYGB7cn0KI0NhbGN1bGF0ZSBzY29yZXMgb2YgY29tYmluYXRpb25zIEEwMCwgQTAxLCBCMDAsIEMwMCwgRDAwCmRpZW10aGkyMDE5JEEwMCA8LSBkaWVtdGhpMjAxOSRNYXRocyArIGRpZW10aGkyMDE5JFBoeXNpY3MgKyBkaWVtdGhpMjAxOSRDaGVtaXN0cnkKaWYoZGllbXRoaTIwMTkkRm9yZWlnbl9sYW5ndWFnZV9jb2RlID09ICdOMScpIHsKICBkaWVtdGhpMjAxOSRBMDEgPC0gZGllbXRoaTIwMTkkTWF0aHMgKyBkaWVtdGhpMjAxOSRQaHlzaWNzICsgZGllbXRoaTIwMTkkRm9yZWlnbl9sYW5ndWFnZQp9CmRpZW10aGkyMDE5JEIwMCA8LSBkaWVtdGhpMjAxOSRNYXRocyArIGRpZW10aGkyMDE5JENoZW1pc3RyeSArIGRpZW10aGkyMDE5JEJpb2xvZ3kKZGllbXRoaTIwMTkkQzAwIDwtIGRpZW10aGkyMDE5JExpdGVyYXR1cmUgKyBkaWVtdGhpMjAxOSRIaXN0b3J5ICsgZGllbXRoaTIwMTkkR2VvZ3JhcGh5CmlmKGRpZW10aGkyMDE5JEZvcmVpZ25fbGFuZ3VhZ2VfY29kZSA9PSAnTjEnKSB7CiAgZGllbXRoaTIwMTkkRDAwIDwtIGRpZW10aGkyMDE5JE1hdGhzICsgZGllbXRoaTIwMTkkTGl0ZXJhdHVyZSArIGRpZW10aGkyMDE5JEZvcmVpZ25fbGFuZ3VhZ2UKfQpoZWFkKGRpZW10aGkyMDE5KQoKI0NhbGN1bGF0ZSBhdmVyYWdlIG9mIG5hdHVyYWwgc2NpZW5jZSBjb21iaW5hdGlvbiBhbmQgc29jaWFsIHNjaWVuY2UgY29tYmluYXRpb24KZGllbXRoaTIwMTkkQXZnX25hdHVyYWxfc2NpZW5jZXMgPC0gKGRpZW10aGkyMDE5JFBoeXNpY3MgKyBkaWVtdGhpMjAxOSRDaGVtaXN0cnkgKyBkaWVtdGhpMjAxOSRCaW9sb2d5KS8zCmRpZW10aGkyMDE5JEF2Z19zb2NpYWxfc2NpZW5jZXMgPC0gKGRpZW10aGkyMDE5JEhpc3RvcnkgKyBkaWVtdGhpMjAxOSRHZW9ncmFwaHkgKyBkaWVtdGhpMjAxOSRDaXRpemVuc2hpcF9lZHVjYXRpb24pLzMKYGBgCgpgYGB7cn0KI1Jlb3JkZXIgYW5kIGNob29zZSBuZWNlc3NhcnkgY29sdW1ucwpkaWVtdGhpMjAxOSA8LSBkaWVtdGhpMjAxOVtjKCdTdHVkZW50X2luZGV4JywgJ1Byb3ZpbmNlX2NvZGUnLCAnUHJvdmluY2VfbmFtZScsICdNYXRocycsICdMaXRlcmF0dXJlJywgJ0ZvcmVpZ25fbGFuZ3VhZ2UnICwnRm9yZWlnbl9sYW5ndWFnZV9jb2RlJywgJ0ZvcmVpZ25fbGFuZ3VhZ2VfbmFtZScsICdQaHlzaWNzJywgJ0NoZW1pc3RyeScsICdCaW9sb2d5JywgJ0F2Z19uYXR1cmFsX3NjaWVuY2VzJywgJ0hpc3RvcnknLCAnR2VvZ3JhcGh5JywgJ0NpdGl6ZW5zaGlwX2VkdWNhdGlvbicsICdBdmdfc29jaWFsX3NjaWVuY2VzJywgJ0EwMCcsICdBMDEnLCAnQjAwJywgJ0MwMCcsICdEMDAnKV0KaGVhZChkaWVtdGhpMjAxOSkKYGBgCgoKYGBge3J9CiNudW1lcmljYWwgZGYgZm9yIGNvcnJlbGF0aW9uIG1hdHJpeApkaWVtdGhpMjAxOV9jb3JyIDwtIGRpZW10aGkyMDE5W2MoNDo2LDk6MjEpXQoKI2NvcnJlbGF0aW9uIG1hdHJpeApkaWVtdGhpMjAxOV9jb3JyX21hdHJpeCA8LSBjb3IoZGllbXRoaTIwMTlfY29yciwgdXNlPSJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQpWaWV3KGRpZW10aGkyMDE5X2NvcnJfbWF0cml4KQoKI2NvcnJlbGF0aW9uIGhlYXRtYXAKZ2djb3JycGxvdChkaWVtdGhpMjAxOV9jb3JyX21hdHJpeCwgaGMub3JkZXIgPSBUUlVFLAogICBsYWIgPSBUUlVFKQpgYGAKCmBgYHtyfQojTnVtYmVyIG9mIHN0dWRlbnRzIHdobyB0YWtlcyBlYWNoIGZvcmVpZ24gbGFuZ3VhZ2UgdGVzdAp0YWJsZShkaWVtdGhpMjAxOSRGb3JlaWduX2xhbmd1YWdlX25hbWUpCmBgYAoKYGBge3J9CiNOdW1iZXIgb2Ygc3R1ZGVudHMgd2hvIHRvb2sgZWFjaCBzdWJqZWN0CnRvb2tfc3ViamVjdCA8LSBsaXN0KCkKZm9yKGkgaW4gYyg0OjYsIDk6MTEsIDEzOjE1KSkgewogIHByaW50KHBhc3RlKCdUaGUgbnVtYmVyIG9mIHN0dWRlbnRzIHdobyB0b29rIHRoZSBzdWJqZWN0JywgY29sbmFtZXMoZGllbXRoaTIwMTlbaV0pLCAnaXMnLCBzdW0oIWlzLm5hKGRpZW10aGkyMDE5WyxpXSkgPT0gVFJVRSkpKSAKfQpgYGAKCmBgYHtyfQojTnVtYmVyIG9mIHN0dWRlbnRzIHdobyBhcmUgZWxpZ2libGUgdG8gYmUgY29uc2lkZXJlZCBmb3IgYWRtaXNzaW9uIHdpdGggZWFjaCBjb21iaW5hdGlvbiBBMDAsIEEwMSwgQjAwLCBDMDAsIEQwMApjb21iaW5hdGlvbl9lbGlnaWJsZSA8LSBsaXN0KCkKZm9yKGkgaW4gYygxNzoyMSkpIHsKICBwcmludChwYXN0ZSgnVGhlIG51bWJlciBvZiBzdHVkZW50cyB3aG8gYXJlIGVsaWdpYmxlIHRvIGJlIGNvbnNpZGVyZWQgZm9yIGNvbWJpbmF0aW9uJywgY29sbmFtZXMoZGllbXRoaTIwMTlbaV0pLCAnaXMnLCBzdW0oIWlzLm5hKGRpZW10aGkyMDE5WyxpXSkgPT0gVFJVRSkpKSAKICBjb21iaW5hdGlvbl9lbGlnaWJsZVtbaS0xNl1dID0gdGFibGUoIWlzLm5hKGRpZW10aGkyMDE5WyxpXSksIGRubiA9IHBhc3RlKGNvbG5hbWVzKGRpZW10aGkyMDE5KVtpXSkpCn0KY29tYmluYXRpb25fZWxpZ2libGUKYGBgCgpgYGB7cn0KI051bWJlciBvZiBzdHVkZW50cyB3aG8gdG9vayBhbGwgbmF0dXJhbCBzY2llbmNlIHN1YmplY3RzLCBhbGwgc29jaWFsIHNjaWVuY2Ugc3ViamVjdHMsIG9yIGFsbCBvZiBib3RoCnByaW50KHBhc3RlKCdUaGUgbnVtYmVyIG9mIHN0dWRlbnRzIHdobyB0b29rIGFsbCBuYXR1cmFsIHNjaWVuY2Ugc3ViamVjdHMgaXMnLCBzdW0oIWlzLm5hKGRpZW10aGkyMDE5WywxM10pID09IFRSVUUpKSkKcHJpbnQocGFzdGUoJ1RoZSBudW1iZXIgb2Ygc3R1ZGVudHMgd2hvIHRvb2sgYWxsIHNvY2lhbCBzY2llbmNlIHN1YmplY3RzIGlzJywgc3VtKCFpcy5uYShkaWVtdGhpMjAxOVssMTddKSA9PSBUUlVFKSkpCnByaW50KHBhc3RlKCdUaGUgbnVtYmVyIG9mIHN0dWRlbnRzIHdobyB0b29rIGFsbCBuYXR1cmFsIGFuZCBzb2NpYWwgc2NpZW5jZSBzdWJqZWN0cyBpcycsIHN1bSghaXMubmEoZGllbXRoaTIwMTlbLDEzXSkgPT0gVFJVRSAmICFpcy5uYShkaWVtdGhpMjAxOVssMTddKSA9PSBUUlVFKSkpCmBgYAoKCmBgYHtyfQojRmluZCB0aGUgbWF4aW11bSBzY29yZSBmb3IgZWFjaCBjb2x1bW4KZm9yKGkgaW4gYyg0OjYsOToyMSkpIHsKICBwcmludChwYXN0ZSgnVGhlIG1heGltdW0gc2NvcmUgb2YnLGNvbG5hbWVzKGRpZW10aGkyMDE5KVtpXSwnaXMnLCBtYXgoZGllbXRoaTIwMTlbLGldLCBuYS5ybSA9IFRSVUUpKSkKfQpgYGAKCmBgYHtyfQpoaXN0b2dyYW1fb3V0IDwtIGxpc3QoKQpmb3IoaSBpbiBjKDQ6Niw5OjIxKSkgewogIHggPSBkaWVtdGhpMjAxOVssaV0KICBoaXN0b2dyYW1fb3V0W1tpXV0gPC0gZ2dwbG90KGRhdGEuZnJhbWUoeCksIGFlcyh4KSkgKyAKICAgIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4xLCBjb2xvcj0iYmxhY2siLCBmaWxsPSJibHVlIikgKwogICAgbGFicyh0aXRsZT1wYXN0ZSgiU2NvcmUgaGlzdG9ncmFtIGZvciIsY29sbmFtZXMoZGllbXRoaTIwMTkpW2ldKSwgeD1jb2xuYW1lcyhkaWVtdGhpMjAxOSlbaV0sIHk9IkNvdW50IikgKyAKICAgIGdlb21fdmxpbmUoZGF0YSA9IGRpZW10aGkyMDE5LCB4aW50ZXJjZXB0ID0gbWVhbihkaWVtdGhpMjAxOVssaV0sIG5hLnJtID0gVFJVRSksIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxKQp9CiAgCiAgcHJpbnQocGFzdGUoJ1RoZSBtZWFuIHNjb3JlIG9mJywgY29sbmFtZXMoZGllbXRoaTIwMTkpW2ldLCAnaXMnLCBtZWFuKGRpZW10aGkyMDE5WyxpXSkpKQogIApoaXN0b2dyYW1fb3V0CgpzdW1tYXJ5X3Njb3Jlc19zdWJqZWN0cyA8LSBkYXRhLmZyYW1lKG1hdHJpeCgwLCBuY29sID0gMjIsIG5yb3cgPSAxMSkpCm5hbWVzKHN1bW1hcnlfc2NvcmVzX3N1YmplY3RzKSA8LSBjKCdOdW1iZXIgb2Ygc3R1ZGVudHMgcGFydGljaXBhdGVkJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01pbmltdW0gc2NvcmUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMjV0aCBwZXJjZW50aWxlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01lZGlhbicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNZWFuIHNjb3JlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzc1dGggcGVyY2VudGlsZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNYXhpbXVtIHNjb3JlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ051bWJlciBvZiBzdHVkZW50cyB3aXRoIHNjb3JlcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gMScsCiMxIGlzIHRoZSBjdXRvZmYgc2NvcmUgdG8gYmUgY29uc2lkZXJlZCBmb3IgZ3JhZHVhdGlvbiwgYXBhcnQgZnJvbSBhdmdfbmF0dXJhbF9zY2llbmNlcyBhbmQgYXZnX3NvY2lhbF9zY2llbmNlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTnVtYmVyIG9mIHN0dWRlbnRzIHdpdGggc2NvcmVzIGxlc3MgdGhhbiA1JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1Njb3JlIHdpdGggaGlnaGVzdCBmcmVxdWVuY3kgKG1vZGUpJykKCnN1bW1hcnlfc2NvcmVzX2NvbWJpbmF0aW9ucyA8LSBkYXRhLmZyYW1lKG1hdHJpeCgwLCBuY29sID0gMjIsIG5yb3cgPSAxMSkpCm5hbWVzKHN1bW1hcnlfc2NvcmVzX3N1YmplY3RzKSA8LSBjKCdOdW1iZXIgb2Ygc3R1ZGVudHMgcGFydGljaXBhdGVkJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01pbmltdW0gc2NvcmUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMjV0aCBwZXJjZW50aWxlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01lZGlhbicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNZWFuIHNjb3JlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzc1dGggcGVyY2VudGlsZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNYXhpbXVtIHNjb3JlJywKIzE1IGlzIHVzdWFsbHkgdGhlIGN1dG9mZiAobWluaW11bSkgc2NvcmUgdG8gYmUgY29uc2lkZXJlZCBmb3IgdW5pdmVyc2l0eSBhZG1pc3Npb24KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ051bWJlciBvZiBzdHVkZW50cyB3aXRoIHNjb3JlcyBsZXNzIHRoYW4gMTUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnU2NvcmUgd2l0aCBoaWdoZXN0IGZyZXF1ZW5jeSAobW9kZSknKQpgYGAKCgpgYGB7cn0KdGFibGVfc2NvcmUgPC0gbGlzdCgpCmZvcihpIGluIGMoNDo2LDk6MjEpKSB7CiAgdGFibGVfc2NvcmVbW2ldXSA9IHRhYmxlKGRpZW10aGkyMDE5WyxpXSwgZG5uID0gcGFzdGUoY29sbmFtZXMoZGllbXRoaTIwMTkpW2ldLCdfc2NvcmVzJykpCn0KCmZvcihpIGluIGMoNDo2LDk6MjEpKSB7CiAgVmlldyh0YWJsZV9zY29yZVtbaV1dKQp9CiN0YWJsZV9zY29yZQpgYGAKCmBgYHtyfQpzdW1tYXJ5KGRpZW10aGkyMDE5WywzXSkKYGBgCgpgYGB7cn0KcHJvdmluY2VfZnJlcXVlbmN5IDwtIHRhYmxlKGRpZW10aGkyMDE5WywzXSkKICNzb3J0KHByb3ZpbmNlX2ZyZXF1ZW5jeSwgZGVjcmVhc2luZyA9IEZBTFNFKSAKcHJvdmluY2VfZnJlcXVlbmN5IDwtY291bnQoZGllbXRoaTIwMTksIFByb3ZpbmNlX25hbWUpCm5hbWVzKHByb3ZpbmNlX2ZyZXF1ZW5jeSkgPC0gYygnUHJvdmluY2UnLCAnRnJlcXVlbmN5JykKcHJvdmluY2VfZnJlcXVlbmN5IDwtIHByb3ZpbmNlX2ZyZXF1ZW5jeVtvcmRlcigtcHJvdmluY2VfZnJlcXVlbmN5JEZyZXF1ZW5jeSksXQpwYXIobGFzPTIpClZpZXcocHJvdmluY2VfZnJlcXVlbmN5KQoKZ2dwbG90KGRhdGE9cHJvdmluY2VfZnJlcXVlbmN5LCBhZXMoeD1yZW9yZGVyKFByb3ZpbmNlLEZyZXF1ZW5jeSkseT1GcmVxdWVuY3kpKSArCiAgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIiwgc3RhdD0iaWRlbnRpdHkiKSArIAogIGNvb3JkX2ZsaXAoKSArCiAgZ2d0aXRsZShwYXN0ZSgnQmFycGxvdCBvZiBudW1iZXIgb2Ygc3R1ZGVudHMgYnkgcHJvdmluY2UnKSkgKwogIGxhYnMoeCA9ICJQcm92aW5jZSIsIHkgPSAiTnVtYmVyIG9mIHN0dWRlbnRzIikgKwogIGdlb21fdGV4dCgKICAgIGFlcyhsYWJlbCA9IEZyZXF1ZW5jeSksIGNvbG91ciA9ICJyZWQiLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDMsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApCgpgYGAKCgpgYGB7cn0KYmFycGxvdF9tZWFuIDwtIGxpc3QoKQpmb3IoaSBpbiBjKDQ6Niw5OjIxKSkgewogIHggPC0gYWdncmVnYXRlKGRpZW10aGkyMDE5WyxpXSB+IGRpZW10aGkyMDE5JFByb3ZpbmNlX25hbWUsIGRpZW10aGkyMDE5LCBtZWFuKQogIG5hbWVzKHgpIDwtIGMoJ1Byb3ZpbmNlJywgJ01lYW4nKQogIHggPC0geFtvcmRlcih4JE1lYW4pLF0KICAKICBiYXJwbG90X21lYW5bW2ldXSA8LSBnZ3Bsb3QoZGF0YT14LCBhZXMoeD1yZW9yZGVyKFByb3ZpbmNlLE1lYW4pLHk9TWVhbikpICsKICBnZW9tX2Jhcihwb3NpdGlvbj0iZG9kZ2UiLHN0YXQ9ImlkZW50aXR5IikgKyAKICBjb29yZF9mbGlwKCkgKwogIGdndGl0bGUocGFzdGUoJ0JhcnBsb3QgZm9yIG1lYW4gb2YnLCBjb2xuYW1lcyhkaWVtdGhpMjAxOSlbaV0sICdieSBwcm92aW5jZScpKSArIAogIGxhYnMoeCA9ICJQcm92aW5jZSIsIHkgPSAiTWVhbiBzY29yZSIpICsKICBnZW9tX3RleHQoCiAgICBhZXMobGFiZWwgPSBNZWFuKSwgY29sb3VyID0gInJlZCIsCiAgICBoanVzdCA9IC0wLjUsIHNpemUgPSAzLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgKQp9CmJhcnBsb3RfbWVhbgpgYGAKCgoK